import json
import random
from pathlib import Path
from dataclasses import dataclass
from typing import NamedTuple, Dict, Literal, Tuple, cast
KNOCKOUT_THRESHOLD = 35
KNOCKOUT_COLD = "{loser}被击晕了无法继续进行比赛，胜利者是{winner}"

# ---------------------------------------------------
class PunchProfile(NamedTuple):
    choices: int
    threshold: int
    hit_damage: int
    block_damage: int
    pre_msg: str
    hit_msg: str
    blocked_msg: str
    dodge_msg: str  # 新增闪避消息

    knockout_possible: bool = False

    def is_hit(self):
        return random.randint(1, self.choices) <= self.threshold

    def is_dodge(self):
        # 闪避的判定，可以根据需要调整闪避的难易程度
        return random.randint(1, 100) <= 20  # 假设闪避成功率为20%
# ---------------------------------------------------

@dataclass
class Player:
    name: str
    best: int
    weakness: int
    is_computer: bool
    punch_profiles: Dict[Literal[1, 2, 3, 4], PunchProfile]
    damage: int = 0
    score: int = 0
    # ---------------------------------------------------
    knockedout: bool = False
    round_damage: int = 0  # 新增变量，记录每一轮受到的伤害
    total_damage_dealt: int = 0  # 新增变量，记录总共造成的伤害
    # ---------------------------------------------------
    def get_punch_choice(self) -> Literal[1, 2, 3, 4]:
        if self.is_computer:
            return random.randint(1, 4)
        while True:
            try:
                punch = int(input(f"{self.name}的招式是？"))
                if 1 <= punch <= 4:
                    return punch
                else:
                    print("无效的拳法，请输入1-4之间的数字。")
            except ValueError:
                print("请输入一个数字。")


def get_vulnerability(player_name):     # 输入玩家弱点
    while True:
        try:
            return int(input(f"{player_name}的弱点是？"))
        except ValueError:
            print("请输入一个数字。")


def get_excel(player2name):     # 输入玩家擅长
    while True:
        try:
            punch = int(input(f"{player2name}擅长的拳法是？"))
            if 1 <= punch <= 4:
                return punch
            else:
                print("请输入正确的拳法序号。")
        except ValueError:
            print("请输入拳法序号。")


# difficulty
def get_opponent_stats(difficulty: int) -> Tuple[int, int]:
    # ---------------------------------------------------
    # 根据difficulty对难度调整对手的最佳和弱点
    opponent_best = random.randint(1, 4) + difficulty
    opponent_weakness = random.randint(1, 4) + difficulty
    while opponent_best == opponent_weakness:
        opponent_best = random.randint(1, 4) + difficulty
        opponent_weakness = random.randint(1, 4) + difficulty
    return opponent_best, opponent_weakness


def read_punch_profiles(filepath: Path) -> Dict[Literal[1, 2, 3, 4], PunchProfile]:
    with open(filepath, encoding='utf-8') as f:
        punch_profiles_dict = json.load(f)
    return {
        cast(Literal[1, 2, 3, 4], int(key)): PunchProfile(**value)
        for key, value in punch_profiles_dict.items()
    }


def play_round(round_number: int, player: Player, opponent: Player) -> None:
    print(f"第{round_number}轮次。\n开始....\n")
    if opponent.score >= 2 or player.score >= 2:
        return
    consecutive_hits = 0
    for _ in range(7):
        if consecutive_hits >= 3:
            active, passive = passive, active
            consecutive_hits = 0

        if random.randint(1, 10) > 5:
            punch = opponent.get_punch_choice()
            active = opponent
            passive = player
        else:
            punch = player.get_punch_choice()
            active = player
            passive = opponent

        punch_profile = active.punch_profiles[punch]
        if punch == active.best:
            active.damage += 2

        print(punch_profile.pre_msg.format(opponent=opponent, player=player))

        if passive.weakness == punch or punch_profile.is_hit():
            print(punch_profile.hit_msg.format(opponent=opponent, player=player))
            if punch_profile.knockout_possible and active.damage > KNOCKOUT_THRESHOLD:
                if active is opponent:
                    player.knockedout = True
                    break
                else:
                    opponent.knockedout = True
                    break
            if active is opponent:
                opponent.total_damage_dealt += punch_profile.hit_damage
                opponent.damage += punch_profile.hit_damage
                player.round_damage += punch_profile.hit_damage
            else:
                player.total_damage_dealt += punch_profile.hit_damage
                player.damage += punch_profile.hit_damage
                opponent.round_damage += punch_profile.hit_damage
            consecutive_hits += 1
        elif punch_profile.is_dodge():
            print(punch_profile.dodge_msg.format(opponent=opponent, player=player))
            active, passive = passive, active
        else:
            print(punch_profile.blocked_msg.format(opponent=opponent, player=player))
            consecutive_hits = 0

        if player.knockedout or opponent.knockedout:
            break

    player.damage = player.round_damage // 2
    opponent.damage = opponent.round_damage // 2
    player.round_damage = 0
    opponent.round_damage = 0

    if player.damage > opponent.damage:
        print(f"{player.name}获得了第{round_number}场胜利")
        player.score += 1
    elif opponent.damage > player.damage:
        print(f"{opponent.name}获得了第{round_number}场胜利")
        opponent.score += 1


def read_punch_profiles(filepath: Path) -> Dict[Literal[1, 2, 3, 4], PunchProfile]:
    with open(filepath, encoding='utf-8') as f:
        punch_profiles_dict = json.load(f)
    return {
        cast(Literal[1, 2, 3, 4], int(key)): PunchProfile(**value)
        for key, value in punch_profiles_dict.items()
    }


def main() -> None:
    print("拳王争霸小游戏")
    print("由xxx设计创造")
    print("学号: 202312060308")
    print("这个游戏采取三局两胜的规则")
    print("请选择难度：1.简单 2.中等 3.困难")
    # ---------------------------------------------------
    while True:
        difficulty = input("请输入难度等级 :")
        if difficulty in ['1', '2', '3']:
            difficulty = int(difficulty) - 1
            break
        else:
            print("无效输入，请输入1 2 3 :")  # 将输入转换为索引
    # ---------------------------------------------------
    opponent_name = input("对手名字为：")
    player_name = input("我的名字为：")
    player_best = get_excel(player_name)                # 玩家擅长
    player_weakness = get_vulnerability(player_name)    # 玩家弱点

    player = Player(
        name=player_name,
        best=player_best,
        weakness=player_weakness,
        is_computer=False,
        punch_profiles=read_punch_profiles(
            Path(__file__).parent / "player.json"
        ),
    )

    opponent_best, opponent_weakness = get_opponent_stats(difficulty)
    opponent = Player(
        name=opponent_name,
        best=opponent_best,
        weakness=opponent_weakness,
        is_computer=True,
        punch_profiles=read_punch_profiles(
            Path(__file__).parent / "oppo.json"
            ),
        )
    for round_number in range(1, 4):
        if player.knockedout or opponent.knockedout:
            break
        play_round(round_number, player, opponent)

    if player.knockedout:
        print(KNOCKOUT_COLD.format(loser=player.name, winner=opponent.name))
    elif opponent.knockedout:
        print(KNOCKOUT_COLD.format(loser=opponent.name, winner=player.name))
    elif opponent.score > player.score:
        print(f"{opponent.name}打败了{player.name}")
    else:
        print(f"{player.name}打败了{opponent.name}")

    print("\n\n比赛结果")
    print(f"{player.name}的总伤害输出：{player.total_damage_dealt}")
    print(f"{opponent.name}的总伤害输出：{opponent.total_damage_dealt}")
    # print(f"{player.name}的胜场数：{player.score}")
    # print(f"{opponent.name}的胜场数：{opponent.score}")
    print("感谢游玩")


if __name__ == "__main__":
    main()